#pragma once

#include <string>
#include <cstdlib>
#include <vector>

class Serializable {
	public:
		virtual ~Serializable() {}
		virtual Serializable* deserialize(const std::string& value) = 0;
};

class Consumer {
	public:
		virtual void consume() = 0;
};

class A: public Serializable{
	int _data;
	A() { }
	
	public:
		static std::vector<A*> myObjects;
		
		A(int value): _data(value) { }
		
		int getData() { return _data;}
		
		Serializable* deserialize(const std::string& value) {
			A* result;
			std::string str(value);
			if (str.substr(0,2).compare("A:")==0) {
				if (str[2]=='0' && str.length()==3) {
					result = new A(0);
				} else {
					result = new A(atoi(str.substr(2).c_str()));
					if (result->_data==0) return NULL;
				}
				A::myObjects.push_back(result);
				return result;
			}
			return NULL;
		}
};

class Aconsumer: public Consumer {
	public:
		void consume() {
			while(A::myObjects.size() > 0) {
				A* a = A::myObjects.back();
				printf("A:%d\n", a->getData());
				A::myObjects.pop_back();
			}
		}
};

class B: public Serializable{
	int _data;
	B() { }
	
	public:
		static std::vector<B*> myObjects;
		
		B(int value): _data(value) { }
		
		int getData() { return _data;}
		
		Serializable* deserialize(const std::string& value) {
			B* result;
			std::string str(value);
			if (str.substr(0,2).compare("B:")==0) {
				if (str[2]=='0' && str.length()==3) {
					result = new B(0);
				} else {
					result = new B(atoi(str.substr(2).c_str()));
					if (result->_data==0) return NULL;
				}
				B::myObjects.push_back(result);
				return result;
			}
			return NULL;
		}
};

class Bconsumer: public Consumer {
	public:
		void consume() {
			while(B::myObjects.size() > 0) {
				B* a = B::myObjects.back();
				printf("B:%d\n", a->getData());
				B::myObjects.pop_back();
			}
		}
};

class C: public Serializable{
	int _data;
	C() { }
	
	public:
		static std::vector<C*> myObjects;
		
		C(int value): _data(value) { }
		
		int getData() { return _data;}
		
		Serializable* deserialize(const std::string& value) {
			C* result;
			std::string str(value);
			if (str.substr(0,2).compare("C:")==0) {
				if (str[2]=='0' && str.length()==3) {
					result = new C(0);
				} else {
					result = new C(atoi(str.substr(2).c_str()));
					if (result->_data==0) return NULL;
				}
				C::myObjects.push_back(result);
				return result;
			}
			return NULL;
		}
		
		void execute() {printf("C:%d\n", _data);}
};

class Cconsumer: public Consumer {
	public:
		void consume() {
			while(C::myObjects.size() > 0) {
				C* a = C::myObjects.back();
				a->execute();
				C::myObjects.pop_back();
			}
		}
};
